﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace IronWiki
{
    [Description("A class containing information about the IronWiki syntax")]
    public class IronWikiSyntax
    {
        [Description("A collection describing all IronWiki classes")]
        public List<IronWikiClass> IronWikiClasses = new List<IronWikiClass>();

        [Description("A collection describing all members of IronWiki classes")]
        public List<IronWikiMember> IronWikiMembers = new List<IronWikiMember>();

        public IronWikiSyntax()
        {
            Assembly asmbly = Assembly.GetExecutingAssembly();
            //IronWikiClasses.Add(new IronWikiClass("Class", "String", "TestType", "()", "A test class"));
            //IronWikiClasses.Add(new IronWikiClass("Class", "Object", "TestType2", "(object TestType)", "A second test class"));
            Type[] types = asmbly.GetTypes();
            foreach (Type t in types) {
                object[] typeattrs = t.GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (typeattrs != null) {
                    foreach (Object attribute in typeattrs) {
                        DescriptionAttribute da = (DescriptionAttribute)attribute;
                        IronWikiClasses.Add(new IronWikiClass("Class", null, t.Name, null, da.Description));
                        MemberInfo[] tmbrs = t.GetMembers();
                        foreach (MemberInfo mi in tmbrs) {
                            object[] mbrattrs = mi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                            if (mbrattrs != null) {
                                foreach (Object ma in mbrattrs) {
                                    DescriptionAttribute mda = (DescriptionAttribute)ma;
                                    switch (mi.MemberType.ToString()) {
                                        case "Method":
                                            MethodInfo method = (MethodInfo)mi;
                                            ParameterInfo[] pinfos = method.GetParameters();
                                            StringBuilder pStr = new StringBuilder();
                                            foreach (ParameterInfo pi in pinfos) {
                                                if (pStr.Length > 0) pStr.Append(", ");
                                                pStr.AppendFormat("{0} {1}", pi.ParameterType, pi.Name);
                                            }
                                            IronWikiMembers.Add(new IronWikiMember("Method", method.ReturnType.ToString(), method.Name, "(" + pStr.ToString() + ")", mda.Description, t.Name));
                                            break;
                                        case "Property":
                                            PropertyInfo prop = (PropertyInfo)mi;
                                            MethodInfo[] accessors = prop.GetAccessors();
                                            StringBuilder aStr = new StringBuilder();
                                            foreach (MethodInfo ai in accessors) {
                                                if (aStr.Length > 0) aStr.Append(", ");
                                                aStr.Append(ai.Name);
                                            }
                                            IronWikiMembers.Add(new IronWikiMember("Property", prop.PropertyType.ToString(), prop.Name, "{" + aStr.ToString() + "}", mda.Description, t.Name));
                                            break;
                                        case "Field":
                                            FieldInfo fld = (FieldInfo)mi;
                                            IronWikiMembers.Add(new IronWikiMember("Field", fld.FieldType.ToString(), fld.Name, null, mda.Description, t.Name));
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

    }

    [Description("The class describing an IronWiki class")]
    public class IronWikiClass : BaseType
    {
        public IronWikiClass(string objectType, string returnType, string name, string argSignature, string description)
            : base(objectType, returnType, name, argSignature, description) { }
    }

    [Description("The class describing an IronWiki member")]
    public class IronWikiMember : BaseType
    {
        [Description("The name of the parent class for the IronWiki member")]
        public string ParentClassName { get; set; }

        public IronWikiMember(string objectType, string returnType, string name, string argSignature, string description, string parentClassName)
            : base(objectType, returnType, name, argSignature, description) 
        {
            ParentClassName = parentClassName;
        }
    }

    public class BaseType
    {
        public string ObjectType { get; set; }
        public string ReturnType { get; set; }
        public string Name { get; set; }
        public string ArgumentSignature { get; set; }
        public string Description { get; set; }

        public BaseType(string objectType, string returnType, string name, string argSignature, string description)
        {
            ObjectType = objectType;
            ReturnType = returnType;
            Name = name;
            ArgumentSignature = argSignature;
            Description = description;
        }
    }
}
